package foundation.web.flow;

import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.hibernate.proxy.HibernateProxyHelper;
import org.zkoss.zk.ui.util.GenericForwardComposer;
import org.zkoss.zul.Combobox;
import org.zkoss.zul.Tab;
import org.zkoss.zul.api.Button;
import org.zkoss.zul.api.Checkbox;
import org.zkoss.zul.api.Datebox;
import org.zkoss.zul.api.Div;
import org.zkoss.zul.api.Doublebox;
import org.zkoss.zul.api.Intbox;
import org.zkoss.zul.api.Longbox;
import org.zkoss.zul.api.Paging;
import org.zkoss.zul.api.Textbox;
import org.zkoss.zul.impl.api.InputElement;

import foundation.common.util.CommonWebUtil;
import foundation.common.util.FiltroBusquedaMacro;
/**
 * This class holds all attribute values for a given composer
 * in order to set them in the future
 * @author fgarcia
 *
 */
public class ComposerStateHolder implements FlowStepStateHolder {

	private static final Log log = LogFactory.getLog(ComposerStateHolder.class);
	
	private static Class<InputElement> inputClass = InputElement.class;
	
	private String composerName ="";
	Map<String, Object> values = new HashMap<String, Object>();


	public Object getValueOf(String inputName) {
		return values.get(inputName);
	}

	/**
	 * Set the hold values to the composer
	 * @param composer composer to restore 
	 * @throws Exception
	 */
	public void setState(AbstractNavigationComposer composer) {
		this.restoreField(composer,values);
	}
	
	private void restoreField(GenericForwardComposer composer,Map<String, Object> valuesOrigin){
		try{
		for (Entry<String, Object> entry : valuesOrigin.entrySet()) {

			String attrName = entry.getKey();

			//the new Field = field to restore
			Field fieldToRestore = composer.getClass().getField(attrName);
			Object objectToRestore = fieldToRestore.get(composer);
			
			//In valueState there are the origin field and value
			ValueState valueStateOrigin = (ValueState)entry.getValue();
			Object value= valueStateOrigin.getValue();
			if(value!=null){
				if(value instanceof Tab){
					Tab inputElemToRestore = (Tab)objectToRestore;
					Tab inputElemOrgin = (Tab)valueStateOrigin.getValue();
					inputElemToRestore.setSelected(inputElemOrgin.isSelected());
					inputElemToRestore.setVisible(inputElemOrgin.isVisible());
					fieldToRestore.set(composer,inputElemToRestore);												
				}
				else if(value instanceof Paging){
					Paging inputElemToRestore = (Paging)objectToRestore;
					Paging inputElemOrgin = (Paging)valueStateOrigin.getValue();
					inputElemToRestore.setTotalSize(inputElemOrgin.getTotalSize());
					inputElemToRestore.setPageSize(inputElemOrgin.getPageSize());
					inputElemToRestore.setPageIncrement(inputElemOrgin.getPageIncrement());
					inputElemToRestore.setActivePage(inputElemOrgin.getActivePage());				
					fieldToRestore.set(composer,inputElemToRestore);												
				}
//				else if(value instanceof GridComposer){
//					GridComposer inputElemToRestore = (GridComposer)objectToRestore;
//					GridComposer inputElemOrgin = (GridComposer)valueStateOrigin.getValue();
//					if(inputElemOrgin.getMold().equals("paging")){
//						inputElemToRestore.setActivePageCustom(inputElemOrgin.getActivePage());
//						fieldToRestore.set(composer,inputElemToRestore);	
//					}											
//				}
				else if(value instanceof FiltroBusquedaMacro){
					FiltroBusquedaMacro inputElemToRestore = (FiltroBusquedaMacro)objectToRestore;
					FiltroBusquedaMacro inputElemOrgin = (FiltroBusquedaMacro)valueStateOrigin.getValue();
					Object selectObject =inputElemOrgin.getSelectedObject();
					if(selectObject!=null){
						inputElemToRestore.setComposer(composer);
						inputElemToRestore.selectedObject(inputElemOrgin.getSelectedObject(),HibernateProxyHelper.getClassWithoutInitializingProxy(inputElemOrgin.getSelectedObject()));
						fieldToRestore.set(composer,inputElemToRestore);	
					}								
				}
//				else if(value instanceof ComboBoxEnum){
//					ComboBoxEnum inputElemToRestore = (ComboBoxEnum)objectToRestore;
//					ComboBoxEnum inputElemOrgin = (ComboBoxEnum)valueStateOrigin.getValue();
//					Object model = inputElemOrgin.getModel();
//					inputElemToRestore.setLabelFirstElement(inputElemOrgin.getLabelFirstElement());
//					inputElemToRestore.setValue(inputElemOrgin.getValue());
//					inputElemToRestore.setModel(inputElemOrgin.getModel());				
//					if(inputElemOrgin.getSelectedItemApi()!=null)
//						inputElemToRestore.setObjectSelect(inputElemOrgin.getSelectedItemApi().getValue());
//					else
//						inputElemToRestore.setObjectSelect(inputElemOrgin.getObjectSelect());
//					inputElemToRestore.setNotSetterValueFirstElem(true);
//					fieldToRestore.set(composer,inputElemToRestore);
//				}
//				else if(value instanceof ComboBoxEntity){
//					ComboBoxEntity inputElemToRestore = (ComboBoxEntity)objectToRestore;
//					ComboBoxEntity inputElemOrgin = (ComboBoxEntity)valueStateOrigin.getValue();
//					inputElemToRestore.setLabelFirstElement(inputElemOrgin.getLabelFirstElement());
//					inputElemToRestore.setValue(inputElemOrgin.getValue());
//					if(inputElemOrgin.getSelectedItemApi()!=null)
//						inputElemToRestore.setObjectSelect(inputElemOrgin.getSelectedItemApi().getValue());
//					if(inputElemOrgin.getObjectSelect()!=null)
//						inputElemToRestore.setObjectSelect(inputElemOrgin.getObjectSelect());
//					inputElemToRestore.setNotSetterValueFirstElem(true);
//					fieldToRestore.set(composer,inputElemToRestore);
//				}
				else if(value instanceof Combobox){
					Combobox inputElemToRestore = (Combobox)objectToRestore;
					Combobox inputElemOrgin = (Combobox)valueStateOrigin.getValue();				
					inputElemToRestore.setValue(inputElemOrgin.getValue());
					fieldToRestore.set(composer,inputElemToRestore);
				}
				else if(value instanceof Checkbox){
					Checkbox inputElemToRestore = (Checkbox)objectToRestore;
					Checkbox inputElemOrgin = (Checkbox)valueStateOrigin.getValue();		
					inputElemToRestore.setChecked(inputElemOrgin.isChecked());
					fieldToRestore.set(composer,inputElemToRestore);
				}
				else if(value instanceof Datebox){
					Datebox inputElemToRestore = (Datebox)objectToRestore;
					Datebox inputElemOrgin = (Datebox)valueStateOrigin.getValue();		
					inputElemToRestore.setValue(inputElemOrgin.getValue());
					fieldToRestore.set(composer,inputElemToRestore);
				}
				else if(value instanceof Doublebox){
					Doublebox inputElemToRestore = (Doublebox)objectToRestore;
					Doublebox inputElemOrgin = (Doublebox)valueStateOrigin.getValue();		
					inputElemToRestore.setValue(inputElemOrgin.getValue());
					fieldToRestore.set(composer,inputElemToRestore);
				}
				else if(value instanceof Longbox){
					Longbox inputElemToRestore = (Longbox)objectToRestore;
					Longbox inputElemOrgin = (Longbox)valueStateOrigin.getValue();		
					inputElemToRestore.setValue(inputElemOrgin.getValue());
					fieldToRestore.set(composer,inputElemToRestore);
				}
				else if(value instanceof Intbox){
					Intbox inputElemToRestore = (Intbox)objectToRestore;
					Intbox inputElemOrgin = (Intbox)valueStateOrigin.getValue();		
					inputElemToRestore.setValue(inputElemOrgin.getValue());
					fieldToRestore.set(composer,inputElemToRestore);
				}			
				else if(value instanceof Textbox){
					Textbox inputElemToRestore = (Textbox)objectToRestore;
					Textbox inputElemOrgin = (Textbox)valueStateOrigin.getValue();		
					inputElemToRestore.setValue(inputElemOrgin.getValue());
					fieldToRestore.set(composer,inputElemToRestore);
				}
				else if(value instanceof Div){
					Div inputElemToRestore = (Div)objectToRestore;
					Div inputElemOrgin = (Div)valueStateOrigin.getValue();		
					inputElemToRestore.setVisible(inputElemOrgin.isVisible());
					fieldToRestore.set(composer,inputElemToRestore);
				}
				else if(value instanceof Button){
					Button inputElemToRestore = (Button)objectToRestore;
					Button inputElemOrgin = (Button)valueStateOrigin.getValue();		
					inputElemToRestore.setVisible(inputElemOrgin.isVisible());
					fieldToRestore.set(composer,inputElemToRestore);
				}
//				else if(value instanceof AbstractBaseMacro){
//					AbstractBaseMacro inputElemToRestore = (AbstractBaseMacro)objectToRestore;		
//					AbstractBaseMacro inputElemOrgin = (AbstractBaseMacro)valueStateOrigin.getValue();
//					Map<String, Object> valuesOriginInput = this.getValuesToSave(inputElemOrgin.getComposer());
//					this.restoreField(inputElemToRestore.getComposer(),valuesOriginInput);
//				}
				else if(value instanceof String && (value.equals(CommonWebUtil.CALLBACK_ARGUMENT) || value.equals(CommonWebUtil.OBJECT_TO_EDIT_ARGUMENT))){
					//fieldToRestore.set(composer,value);
				}
				else {				
					fieldToRestore.set(composer,value);
				}				
			}

		}		
		
		//now it'll call to the methods setter in the composer	
		//composer.callMethods();
		Class objectClass = composer.getClass();
		objectClass.getMethod("callMethods").invoke(composer);		
		}
		catch (Exception e) {
			log.error(e.getMessage());
		}
	}

	/**
	 * Saves a Composer attributes state
	 * @param composer composer to save its statue
	 */
	public void getState(AbstractNavigationComposer composer) {	
		values =this.getValuesToSave(composer);
		composerName=composer!=null?composer.getClass().getSimpleName():"";
	}
	
	
	private Map<String, Object> getValuesToSave(Object object){
		Map<String, Object> valuesToSave =  new HashMap<String, Object>();
		try {		
			//TODO validar si con todos los fields public es suficiente				
			//the next sentences get all "public" field of the composer			
			Field[] fields = object.getClass().getFields();
			for (Field field : fields) {
					ValueState valueState = new ValueState();
					valueState.setField(field);
					valueState.setValue(field.get(object));
					valuesToSave.put(field.getName(), valueState);							
			}
		
		} catch (Exception e) {
			// TODO Auto-generated catch block
			log.error(e.getMessage());		
		}
		return valuesToSave;
		}

	public String getComposerName() {
		return composerName;
	}

	public void setComposerName(String composerName) {
		this.composerName = composerName;
	}

	
	
}
